package main

import "fmt"

//结构体定义: type关键字 结构体名 struct关键字 {属性。。}
//结构体名的大小写（person），不需要挎包调用就小写，需要挎包则大写
//属性名建议全大写，如果之后要做一些json的操作，小写的话会出问题
type person struct {
	Name string
	City string
	Age  int
}

func main() {
	//结构体的实例化
	//结构体本身是个数据类型 int string
	//普通类型的实例化
	p1 := person{
		Name: "zhangsan",
		City: "beijing",
		Age:  20,
	}
	fmt.Printf("%T %v \n", p1, p1)
	fmt.Println(p1.Name)

	var p2 person
	p2.Name = "lisi"
	p2.Age = 30
	p2.City = "guangzhou"
	//打印出的类型是main.person，说明是main包下面的person类型
	fmt.Printf("%T %v \n", p2, p2)

	//指针类型的实例化 *强力推荐*
	//能用指针类型都用指针类型
	p3 := new(person)
	p3.Name = "wangsu"
	fmt.Printf("%T %v \n", p3, p3)

	p4 := &person{
		Name: "wangwu",
		City: "shanghai",
		Age:  18,
	}
	fmt.Printf("%T %v \n", p4, p4)
	fmt.Println((*p4).Name, p4.Name)

	//方法的使用
	//函数可以直接使用函数名调用
	//方法必须先实例化结构体，在通过实例化对象去调用方法
	//printInfo() 函数调用，当前会报错
	p4.printInfo() //方法调用
	p4.setInfo()
	p4.printInfo()
}

//函数定义：func关键字 函数名（接收参数） （返回值） {函数体}
//结构体方法定义：func关键字 (接收者) 函数名（接收参数） （返回值） {函数体}
//比如说现在要定义一个person打印个人信息的行为
//接收者 func(p person)  func(person)
//这个接收者其实是实例化对象，就是上面的p1 p2 p3 p4
func (p person) printInfo() {
	fmt.Printf("姓名：%s, 年龄:%d \n", p.Name, p.Age)
}

//指针接收者
func (p *person) setInfo() {
	//func(p person) p = p4 因为是普通类型，背后是一个copy值的操作
	//func(p *person) p = p4 指针类型，数据发生引用传递，同时最终指向同一个内存地址
	p.Name = "aoteman"
	fmt.Println(p)

	//&{aoteman shanghai 18}
	//json
	//a := `{"name":"aoteman","age":18,"city":"shanghai"}`
}
